package com.engine.Mangers;

import java.util.Date;
import java.util.List;

import org.hibernate.Session;

import com.util.EngineUtil;
import com.wfe.db.SessionUtil;
import com.wfe.db.WorkFlowEngineQueryUtil;
import com.wfe.generics.BussinessTask;
import com.wfe.mapping.client.WfProjectStatus;
import com.wfe.mapping.client.WfProjectTask;
import com.wfe.mapping.client.WfProjectTaskStatus;
import com.wfe.mapping.client.WfTask;
import com.wfe.mapping.client.WfTaskType;

/**
 * @author kareem_yehya
 * @since 25 March 2009 * @version 1.0.0.1 the first status is 5 (created) Method to load all tasks Method to change task status Method to route tasks
 *        1- Execute Task when its status is assigned 2- Update Task Status after execution 3- Call Router to change next tasks status to assigned
 * */

public class TaskManger implements Runnable
{

	private static long taskNumber = 0;
	private static String wfTaskParameter = "";
	private static int fetchSize = 100;
	private static String fetchSizeParameter = "";

	WfProjectTaskStatus inprocessStatus = getWfProjectTaskStatusByID(3l);

	public void run()
	{

		while(true)
		{
			try
			{
				// ------------------------- assigned process tasks
				System.out.println("Resume Task manger main Thread");
				// TODO should change static number to parmaeter
				List<WfProjectTask> taskList = loadAssignedProcessTasks(fetchSize);

				if(taskList.size() > 0)
				{
					// change status immediatly
					/**
					 * Change status immediatly to inprocess to not be collected by another thread
					 * 
					 * */
					for(WfProjectTask projectTask : taskList)
					{//
						projectTask.setWfProjectTaskStatus(inprocessStatus);// Inprocess
						projectTask.setStartTime(new Date());// to collected by repair automatic tasks
						updateTask(projectTask);
					}

					for(WfProjectTask projectTask : taskList)
					{
						boolean isSuccess = executeTask(projectTask);
						// ----------
						if(isSuccess)

						{
							// -------------------need route------------------
							// Task ID to get it after execution
							WfProjectTask task = getWfProjectTaskById(projectTask.getRecid());
							// if(task.getWfProjectTaskStatus().getRecid() != 7) // problem
							if(!task.getWfProjectTaskStatus().getRecid().equals(7)) // problem
							{
								// Router.route(task);
								/**
								 * Ready for route the task router will use
								 * 
								 * 
								 * */

								task.setIsRouted(false);// /ready for route
								updateTask(task);
							}

						}

					}

				}
				else
				{
					// AWFLogger.info("No Any new Automatic Tasks To Execute");
					System.out.println("No Any new Automatic Tasks To Execute");
				}

				Thread.sleep(5000);
			}catch(Exception e)
			{
				e.printStackTrace();
			}
		}

	}

	/**
	 * @author kareem_yehya
	 * @since 05 April 2009 <br>
	 *        Task Execute
	 * 
	 * 
	 * 
	 * */

	private boolean executeTask(WfProjectTask projectTask)
	{
		Class businessClass;
		try
		{
			businessClass = Class.forName(projectTask.getWfTask().getClazz());
		}catch(ClassNotFoundException e1)
		{
			System.out.println(" No Class Definition in DB For Automatic Task Name = " + projectTask.getWfTask().getName());
			System.out.println(" Task Configuration Missing Information Automatic Task ID = " + projectTask.getWfTask().getRecid());
			e1.printStackTrace();
			return false;
		}

		BussinessTask task = null;
		try
		{
			// ------------ ignore processed tasks---------------------//
			if(projectTask.getIsProcessed() != null && projectTask.getIsProcessed().booleanValue())
			{
				return false;

			}

			// -------------------------------------------------------------///
			task = (BussinessTask) businessClass.newInstance();
			task.setRecid(projectTask.getRecid());
			task.setCreationTime(projectTask.getCreationTime());
			// task.setEndTime(projectTask.getEndTime());// ///how
			task.setStartTime(new Date());
			task.setWfPlanTask(projectTask.getWfPlanTask());
			task.setWfProject(projectTask.getWfProject());
			task.setWfTask(projectTask.getWfTask());
			task.setWfTaskType(projectTask.getWfTaskType());
			// task.setWfProjectTaskStatus(getWfProjectTaskStatusByID(3l));//
			// Inprocess
			changeTaskBeforeExecute(task);
			System.out.println(" About To Execute task name = " + task.getWfTask().getName() + " Start Time = " + task.getStartTime());

			task.execute();
			changeTaskAfterExecute(task);
			System.out.println(" Finish execution of task name = " + task.getWfTask().getName() + " End Time = ");
			return true;
		}catch(Exception e)
		{
			if(task != null)
				System.out.println(" Finish execution With Error iside it of task name = " + task.getWfTask().getName() + " End Time = " + task.getEndTime());
			e.printStackTrace();
			return false;
		}

	}

	private void changeTaskBeforeExecute(BussinessTask task)
	{
		WfProjectTask pTask = getWfProjectTaskById(task.getRecid());
		// pTask.setWfProjectTaskStatus(getWfProjectTaskStatusByID(3l));//
		// inprocess
		pTask.setStartTime(new Date());
		pTask.setUserId(0l);
		pTask.setGroupId(0l);
		updateTask(pTask);

	}

	private void changeTaskAfterExecute(BussinessTask task)
	{
		WfProjectTask pTask = getWfProjectTaskById(task.getRecid());
		pTask.setIsProcessed(true);
		pTask.setEndTime(new Date());
		pTask.setIsRouted(false);// do not remove
		updateTask(pTask);

	}

	/**
	 * @author kareem_yehya
	 * @since 05 April 2009 <br>
	 *        Load unprocessed process tasks
	 * 
	 * 
	 * */

	public List<WfProjectTask> loadAssignedProcessTasks(int maxresults)
	{
		Session session = null;
		List<WfProjectTask> tasklist = null;
		try
		{
			WfTaskType taskType = getwfTaskTypeByTypeID(3); // automatic
			WfProjectTaskStatus taskStatus = getWfProjectTaskStatusByID(4); // assigned
			WfProjectStatus projectStatus = getWfProjectStatusByID(2); // inprocess

			// ------------

			session = SessionUtil.getSession();
			if(taskNumber > 0)
			{
				WfTask wfTask = getWfTask(taskNumber);
				tasklist = WorkFlowEngineQueryUtil.getProjectTasks(session, projectStatus, maxresults, taskType, taskStatus, false, wfTask);
			}
			else
			{
				tasklist = WorkFlowEngineQueryUtil.getProjectTasks(session, projectStatus, maxresults, taskType, taskStatus, false);
			}
			// close session
			return tasklist;

		}catch(Exception e)
		{
			e.printStackTrace();
		}

		finally
		{

			EngineUtil.closeSession(session);
		}
		return null;
	}

	/**
	 * @author kareem_yehya
	 * @since 05 April 2009 <br>
	 *        Load Task Type
	 * 
	 * 
	 * */

	public WfTaskType getwfTaskTypeByTypeID(long tasktype)
	{

		Session session = null;
		try
		{
			session = SessionUtil.getSession();
			WfTaskType taskType = WorkFlowEngineQueryUtil.getWfTaskType(session, tasktype);

			return taskType;

		}catch(Exception e)
		{
			e.printStackTrace();
		}finally
		{

			EngineUtil.closeSession(session);
		}

		return null;
	}

	private WfProjectTaskStatus getWfProjectTaskStatusByID(long i)
	{

		Session session = null;
		try
		{
			session = SessionUtil.getSession();
			WfProjectTaskStatus projectTaskStatus = WorkFlowEngineQueryUtil.getWfProjectTaskStatusByID(i, session);

			return projectTaskStatus;

		}catch(Exception e)
		{
			e.printStackTrace();
		}finally
		{

			EngineUtil.closeSession(session);
		}

		return null;

	}

	private WfProjectTask getWfProjectTaskById(Long recid)
	{
		Session session = null;
		try
		{
			session = SessionUtil.getSession();
			WfProjectTask projectTask = WorkFlowEngineQueryUtil.getWfProjectTask(session, recid, 10).get(0);

			return projectTask;

		}catch(Exception e)
		{
			e.printStackTrace();
		}finally
		{

			EngineUtil.closeSession(session);
		}

		return null;
	}

	private void updateTask(WfProjectTask task)
	{
		Session session = null;
		try
		{
			session = SessionUtil.getSession();
			WorkFlowEngineQueryUtil.updateWfProjectTask(task, session);

		}catch(Exception e)
		{
			e.printStackTrace();
		}finally
		{

			EngineUtil.closeSession(session);
		}

	}

	private WfProjectStatus getWfProjectStatusByID(long i)
	{
		Session session = null;
		try
		{
			session = SessionUtil.getSession();
			WfProjectStatus projectStatus = WorkFlowEngineQueryUtil.getwfProjectStatusByID(i, session);
			return projectStatus;
		}catch(Exception e)
		{
			e.printStackTrace();
		}finally
		{

			EngineUtil.closeSession(session);

		}
		return null;
	}

	private static WfTask getWfTask(long wfTaskID)
	{

		Session session = null;
		try
		{
			session = SessionUtil.getSession();
			WfTask task = WorkFlowEngineQueryUtil.getWfTask(session, wfTaskID);
			return task;
		}catch(Exception e)
		{
			e.printStackTrace();
		}finally
		{

			EngineUtil.closeSession(session);

		}
		return null;

	}

	public static void main(String args[])
	{

		// ---------------------------------------------------

		if(args.length == 2)
		{

			wfTaskParameter = args[0];

			if(wfTaskParameter != null && !wfTaskParameter.equals(""))
			{
				taskNumber = Long.parseLong(wfTaskParameter);
				System.out.println("WF task = " + wfTaskParameter);
			}

			fetchSizeParameter = args[1];
			if(fetchSizeParameter != null && !fetchSizeParameter.equals(""))
			{
				fetchSize = Integer.parseInt(fetchSizeParameter);
				System.out.println("fetchSize = " + fetchSize);
			}
		}

		// ------------------------------------------------

		else
		{
			System.out.println("WF task = " + "All Tasks  Types");
			System.out.println("default fetsh size = " + fetchSize);
		}
		(new Thread(new TaskManger())).start();

		// new TaskManger().run();
	}

}
